#ifndef __INCUBATOR__
#define __INCUBATOR__

//#include "backend-fs.h"
#include <st.h>
#include "protocol.h"
#include "backend-fs.h"
#include "ursax.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef int (*breed_chunk_write_t)(st_netfd_t stfd, uint32_t volumeid, uint32_t index, uint64_t version, uint64_t offset, void* buf, uint64_t size);

struct Chunk;
struct Incubation
{
	struct Chunk* chunk;
	uint64_t since_version;		// 0 for full incubation
	uint64_t progress, chunk_size;
	st_thread_t thread;
	st_netfd_t target;
	struct CSEP to;
	char* buf;
	uint32_t get_journal_flag;
	breed_chunk_write_t chunkwrite;
};
typedef struct Incubation Incubation2; // extend Incubation
#define INCUBATE_GET_JOURNAL_WITH_SUSPEND(flag) (!(flag & GET_JOURNAL_NO_SUSPEND))
#define INCUBATE_GET_JOURNAL_NO_SUSPEND(flag) ((flag & GET_JOURNAL_NO_SUSPEND))

int incubator_init();

void incubator_fini();

void _write_check_incubation(struct Chunk* chunk, uint64_t offset, uint64_t size, void* buf);
static inline void write_check_incubation(struct Chunk* chunk, uint32_t offset, uint32_t size, void* buf)
{
	if (unlikely(chunk->incubation && chunk->incubation->target)) // target may be NULL when chunk->incubation is not
		_write_check_incubation(chunk, offset, size, buf);
}

int start_incubate(struct Chunk* chunk, uint64_t since_version, uint32_t ip, uint16_t port);

int add_write_suspended_chunks(uint32_t volumeid, uint32_t index);
int check_write_suspended_chunks(uint32_t volumeid, uint32_t index);

int check_wait_write_suspended(uint32_t volumeid, uint32_t index);
bool check_write_suspend(uint32_t volumeid, uint32_t index);

void remove_write_suspended_chunks(uint32_t volumeid, uint32_t index);

int add_new_replica_record(uint32_t volumeid, uint32_t index, uint32_t ip, uint16_t port);

bool check_new_replica_record(struct CSEP servers[], uint32_t volumeid, uint32_t index);

void remove_new_replica_record(uint32_t volumeid, uint32_t index);

int be_chunk_set_being_incubated(struct Chunk* chunk);

int be_chunk_unset_being_incubated(struct Chunk* chunk, bool add_chunk);

bool be_chunk_update_being_incubated(struct Chunk* chunk);

int incubation2_send_data(st_netfd_t stfd, uint32_t volumeid, uint32_t index, uint64_t version, uint64_t offset, void* buf, uint64_t size);

int incubation2_send_end(struct Chunk* chunk, st_netfd_t target_stfd, uint64_t version);

int start_incubate2_wait(struct Chunk* chunk, uint64_t since_version, st_netfd_t target, uint32_t ip, uint16_t port, uint32_t get_journal_flag);

#ifdef __cplusplus
}
#endif

#endif
